package com.forgenet.login.controller;

import com.ecwid.consul.v1.health.model.HealthService;
import com.forgenet.message.PacketId;
import com.sparrow.common.util.TokenUtil;
import com.sparrow.common.uuid.TimeUUIDGenerator;
import com.sparrow.servicemgr.consul.ConsulManager;
import com.sparrow.servicemgr.consul.domain.ConsistentServiceSelector;
import com.sparrow.socket.http.anno.HttpMethod;
import com.sparrow.socket.http.anno.HttpPacketClass;
import com.sparrow.socket.http.anno.HttpParam;
import com.sparrow.socket.http.bean.HttpResponse;
import org.bson.Document;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

/**
 * 账号验证
 */
@Component
@HttpPacketClass
public class LoginHttpController {

    private static final Logger logger = LoggerFactory.getLogger(LoginHttpController.class);

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private ConsulManager consulManager;

    @Autowired
    private RedissonClient redisClient;

    @Autowired
    private TimeUUIDGenerator uuidGenerator;

    /**
     * 账号验证
     * @param userName
     * @param password
     * @return
     */
    @HttpMethod(packetId = PacketId.LoginServer.REQ_ACCOUNT_AUTH, result = {})
    public HttpResponse accountAuth(@HttpParam(name = "userName", type = String.class) String userName, @HttpParam(name = "password", type = String.class) String password) {
        HttpResponse response = new HttpResponse(PacketId.LoginServer.REQ_ACCOUNT_AUTH);
        //这里模拟渠道服务器验证
        boolean auth = syncPlatAuth();
        if (auth) {
            Long playerId = getPlayerIdByAccount(userName);
            if (playerId != null) {
                String account = userName;
                response.setCode(1);
                //登录服分配 网关 和 游戏服 使用一致性哈希
                //网关选择
                ConsistentServiceSelector gateSelector = new ConsistentServiceSelector(consulManager, "gate", 100);
                HealthService gateService = gateSelector.selectService("account-" + account);
                response.addResult("gate-ip", gateService.getService().getAddress());
                response.addResult("gate-port", gateService.getService().getPort());
                //游戏服选择
                ConsistentServiceSelector gameSelector = new ConsistentServiceSelector(consulManager, "game", 100);
                HealthService gameService = gameSelector.selectService("account-" + account);
                //redis设置游戏服id
                String gameId = gameService.getService().getId();
                RBucket<String> playerIdToGameData = redisClient.getBucket("player:route:" + account);
                playerIdToGameData.set(gameId);
                //登录服生成包含playerId的token 网关提取出playerId 避免冒充别人的playerId
                String token = TokenUtil.createToken(playerId + "");
                response.addResult("token", token);
            } else {
                response.setCode(0);
            }
        }
        return response;
    }

    private boolean syncPlatAuth() {
        return true;
    }

    public Long getPlayerIdByAccount(String account) {
        //从redis缓存里面取
        RMap<String, Long> accountMap = redisClient.getMap("account:playerId");
        Long playerId = accountMap.get(account);
        if (playerId == null) {
            //没有再从mongodb取
            Query query = new Query(Criteria.where("account").is(account));
            query.fields().include("playerId");
            Document doc = mongoTemplate.findOne(query, Document.class, "player"); // "player" 是 Mongo 集合名
            playerId =  doc != null ? doc.getLong("playerId") : null;
            if (playerId != null) {
                accountMap.put(account, playerId);
            }
        }
        return playerId;
    }

    /**
     * 创建角色
     * @return
     */
    @HttpMethod(packetId = PacketId.LoginServer.REQ_CREATE_ACCOUNT, result = {})
    public HttpResponse createRole(@HttpParam(name = "userName", type = String.class) String userName, @HttpParam(name = "roleName", type = String.class) String roleName) {
        HttpResponse response = new HttpResponse(PacketId.LoginServer.REQ_CREATE_ACCOUNT);
        //网关选择
        ConsistentServiceSelector gateSelector = new ConsistentServiceSelector(consulManager, "gate", 100);
        HealthService gateService = gateSelector.selectService("account-" + userName);
        response.addResult("gate-ip", gateService.getService().getAddress());
        response.addResult("gate-port", gateService.getService().getPort());
        //游戏服选择
        ConsistentServiceSelector gameSelector = new ConsistentServiceSelector(consulManager, "game", 100);
        HealthService gameService = gameSelector.selectService("account-" + userName);
        response.addResult("game-ip", gameService.getService().getAddress());
        response.addResult("game-port", gameService.getService().getPort());
        //redis设置游戏服id
        String gameId = gameService.getService().getId();
        System.out.println("redis绑定游戏服id:" + gameId);
        RBucket<String> playerIdToGameData = redisClient.getBucket("account:route:" + userName);
        playerIdToGameData.set(gameId);

        //生成token 方便网关提取
        String token = TokenUtil.createToken(userName);
        response.addResult("token", token);
        logger.info("create Account:{}", userName);
        response.setCode(1);
        return response;
    }

    @HttpMethod(packetId = PacketId.Consul.REQ_HEATH_CHECK, result = {})
    public HttpResponse reqHealth() {
        logger.info("consul agent 请求健康检查");
        return new HttpResponse(PacketId.Consul.REQ_HEATH_CHECK);
    }
}
